package main

import (
	"context"
	"fmt"
	"github.com/golang/protobuf/ptypes/timestamp"
	"grpc-5/helper"
	"grpc-5/pb/services"
	"io"
	"time"

	"google.golang.org/grpc"
	"log"
)

//需要拷贝根据 Prod.proto 生成的两个文件( Prod.pb.go Prod_grpc.pb.go )
func main() {
	//chrome页面通过get请求访问
	//http://localhost:8080/v1/prod/135?prod_area=101

	//通过rpc访问
	conn, err := grpc.Dial(":8081", grpc.WithTransportCredentials(helper.GetClientCredentials()))
	if err != nil {
		log.Fatalf("连接GRPC服务端失败 %v\n", err)
	}

	defer conn.Close()
	//prod 客户端
	prodClient := services.NewProductServiceClient(conn)
	//获取单个
	getProductStock(err, prodClient)
	//获取多个(列表
	getProductStocks(err, prodClient)
	//获取对象返回
	getProductInfo(err, prodClient)

	//order 客户端
	//使用 postman 请求, post方式, raw=json
	//http://localhost:8080/v1/orders
	/*
		{
		    "order_no": "20210927",
		    "order_money": -96,
		    "user_id": 1001,
		    "order_details": [
		        {"detail_id":20210927,"order_no":"20210927","prod_id":169,"prod_price":9.9,"prod_num":6},
		        {"detail_id":20210927,"order_no":"20210927","prod_id":174,"prod_price":19.9,"prod_num":5}
		    ]
		}
	*/
	orderClient := services.NewOrderServiceClient(conn)
	//创建订单
	newOrder(err, orderClient)

	//用户信息
	userClient := services.NewUserServiceClient(conn)
	//一次请求一次响应模式
	getUserScore(err, userClient)
	//服务端流模式(场景: 客户端操作快, 服务端处理比较慢, 客户端一次性发送, 服务端分批次返回给客户端)
	getUserScoreByServerStream(err, userClient)
	//客户端流模式(场景: 客户端操作慢, 服务端处理比较快, 客户端分批次发送, 服务端一次性返回给客户端)
	getUserScoreByClientStream(err, userClient)
	//双向流模式(场景: 客户端操作快, 服务端处理比较慢, 客户端分批次发送, 服务端分批次返回给客户端)
	getUserScoreByTWS(err, userClient)
}

func getUserScoreByTWS(err error, userClient services.UserServiceClient) {
	users := make([]*services.UserInfo, 0)
	var i int32 = 0
	for i = 0; i < 6; i++ {
		user := &services.UserInfo{UserId: i + 1}
		users = append(users, user)
	}

	stream, err := userClient.GetUserScoreByTWS(context.Background())

	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}

	//共15条数据, 分3次发送
	for i := 0; i < 3; i++ {
		req := new(services.UserScoreRequest)
		req.Users = make([]*services.UserInfo, 0)
		var j int32
		//生成5条用户信息, 假设这是一个耗时的过程
		for j = 1; j <= 5; j++ {
			req.Users = append(req.Users, &services.UserInfo{UserId: j})
		}
		//没生成完成5条发送一次
		stream.Send(req)

		//处理结果
		res, err := stream.Recv()
		//接收完成
		if err == io.EOF {
			break
		}
		//接收失败
		if err != nil {
			log.Fatalf("接收服务端请求失败 %v\n", err)
		}

		//接收数据处理
		fmt.Println(res.Users)
		fmt.Println("--------middle--------")

	}
	fmt.Println("---------------- ----------------")
}

func getUserScoreByClientStream(err error, userClient services.UserServiceClient) {
	users := make([]*services.UserInfo, 0)
	var i int32 = 0
	for i = 0; i < 6; i++ {
		user := &services.UserInfo{UserId: i + 1}
		users = append(users, user)
	}

	stream, err := userClient.GetUserScoreByClientStream(context.Background())

	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}

	//共15条数据, 分3次发送
	for i := 0; i < 3; i++ {
		req := new(services.UserScoreRequest)
		req.Users = make([]*services.UserInfo, 0)
		var j int32
		//生成5条用户信息, 假设这是一个耗时的过程
		for j = 1; j <= 5; j++ {
			req.Users = append(req.Users, &services.UserInfo{UserId: j})
		}
		stream.Send(req)
	}

	//假设服务端处理比较快, 客户端发送完成服务端基本处理完成, 直接接收所有结果
	res, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatalf("接收服务端请求失败 %v\n", err)
	}

	for _, user := range res.Users {
		fmt.Println(user)
	}
	fmt.Println("---------------- ----------------")
}

func getUserScoreByServerStream(err error, userClient services.UserServiceClient) {
	users := make([]*services.UserInfo, 0)
	var i int32 = 0
	//增加5条用户信息
	for i = 1; i < 6; i++ {
		user := &services.UserInfo{UserId: i + 1}
		users = append(users, user)
	}
	//通过 stream 方式获取返回结果
	stream, err := userClient.GetUserScoreByServerStream(context.Background(),
		&services.UserScoreRequest{Users: users},
	)
	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}

	//读取流(stream)
	for {
		//接收
		userRes, err := stream.Recv()
		//流结束
		if err == io.EOF {
			break
		}
		//读取出错了
		if err != nil {
			fmt.Printf("读取服务端流失败 err: %v\n", err.Error())
			break
		}
		//处理接收到的数据
		fmt.Println(userRes.Users)
	}
	fmt.Println("---------------- ----------------")
}

func getUserScore(err error, userClient services.UserServiceClient) {
	users := make([]*services.UserInfo, 0)
	var i int32 = 0
	for i = 0; i < 6; i++ {
		user := &services.UserInfo{UserId: i + 1}
		users = append(users, user)
	}

	userRes, err := userClient.GetUserScore(context.Background(),
		&services.UserScoreRequest{Users: users},
	)

	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}

	fmt.Println(userRes.Users)
	fmt.Println("---------------- ----------------")
}

func newOrder(err error, orderClient services.OrderServiceClient) {
	//秒级别, Unix时间戳
	orderTime := timestamp.Timestamp{Seconds: time.Now().Unix()}
	slice := make([]*services.OrderDetail, 4, 20)
	slice[1] = &services.OrderDetail{
		DetailId:  10,
		OrderNo:   "567",
		ProdId:    196,
		ProdPrice: 9.9,
		ProdNum:   5,
	}
	orderRes, err := orderClient.NewOrder(context.Background(),
		&services.OrderRequest{
			OrderMain: &services.OrderMain{
				OrderId:      100,
				OrderNo:      "酱油1001",
				UserId:       200,
				OrderMoney:   -9.8,
				OrderTime:    &orderTime,
				OrderDetails: slice,
			},
		})

	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}
	fmt.Printf("订单状态 %v, 订单消息: %v\n", orderRes.Status, orderRes.Message)
	fmt.Println("---------------- ----------------")
}

func getProductInfo(err error, prodClient services.ProductServiceClient) {
	prodRes, err := prodClient.GetProductInfo(context.Background(),
		&services.ProdRequest{ProdId: 12})
	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}
	fmt.Println(prodRes)
	fmt.Println("---------------- ----------------")

}

func getProductStocks(err error, prodClient services.ProductServiceClient) {
	prods, err := prodClient.GetProductStocks(context.Background(),
		&services.QuerySize{Size: 3})
	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}
	for _, res := range prods.Prodres {
		fmt.Printf("商品库存为: %v\n", res.ProdStock)
	}
	fmt.Println("---------------- ----------------")
}

func getProductStock(err error, prodClient services.ProductServiceClient) {
	prodRes, err := prodClient.GetProductStock(context.Background(),
		&services.ProdRequest{ProdId: 12, ProdArea: services.ProdAreas_B})
	if err != nil {
		log.Fatalf("请求GRPC服务端失败 %v\n", err)
	}
	fmt.Println(prodRes.ProdStock)
	fmt.Println("---------------- ----------------")
}
